home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Entertainment / MacMud / Sockets / socket.stdio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-04-05  |  8.2 KB  |  520 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    A really hacked up stdio interface for the MacTCP socket library
  3.  *    
  4.  *    Summer 1989, Tom Milligan, University of Toronto Computing Services
  5.  *
  6.  *
  7.  *    routines:
  8.  *
  9.  *        fdopen
  10.  *        fileno
  11.  *        fgetc
  12.  *        ungetc
  13.  *        fread
  14.  *        fputc
  15.  *        fwrite
  16.  *        fprintf
  17.  *        fflush
  18.  *        fclose
  19.  *        ferror
  20.  *        feof
  21.  *        clearerr
  22.  *
  23.  *    hacks:
  24.  *
  25.  *        the stdio data are stored in the socket descriptor. fdopen() calls
  26.  *        simply return a pointer to the descriptor. The first call per
  27.  *        socket initializes stdio for both read and write. (The "rw"
  28.  *        parameter to fdopen() is ignored.) The first fclose() will destroy
  29.  *        all stdio streams open on the socket.
  30.  *
  31.  *        ungetc will return EOF if the buffer is full.
  32.  *
  33.  *        printf uses a fixed size buffer to build the message.
  34.  *
  35.  *    non-blocking i/o
  36.  *
  37.  *        all read operations which would block return EOF with errno set 
  38.  *        to EWOULDBLOCK courtesy of the read() call.
  39.  *
  40.  *        write operations hide the EINPROGRESS 'error' from the write()
  41.  *        call, but generate EALREADY when a second operation is attempted.
  42.  *
  43.  *        NOTE: the write() call ties up the stdio buffer until it finishes. 
  44.  *
  45.  *        How to code a write operation....
  46.  *
  47.  *        for(;;)
  48.  *        {
  49.  *            errno = 0;
  50.  *            if (s_fprintf(stream, blah, blah) != EOF)
  51.  *                break;
  52.  *            
  53.  *            if (errno == EALREADY)
  54.  *            {
  55.  *                Handle_Mac_Events();
  56.  *                continue;
  57.  *            }
  58.  *            else
  59.  *            {
  60.  *                a real error ...
  61.  *            }
  62.  *        }
  63.  *
  64.  *        How to code a read ...
  65.  *
  66.  *        for(;;)
  67.  *        {
  68.  *            errno = 0;
  69.  *            c = s_fgetc(inFile);
  70.  *            if (c != EOF)
  71.  *                break;
  72.  *            if (errno == EWOULDBLOCK || errno == EALREADY)
  73.  *            {
  74.  *                Handle_Mac_Events();
  75.  *                continue;
  76.  *            }
  77.  *            else if (errno == 0)
  78.  *            {
  79.  *                a real end of file ...
  80.  *            }
  81.  *            else
  82.  *            {
  83.  *                a real error ...
  84.  *            }
  85.  *        }
  86.  */
  87.  
  88.      
  89. #include <Events.h>
  90. #include <memory.h>
  91. #include <types.h>
  92.  
  93. #include <stdio.h>
  94.  
  95. #include <sys/types.h>
  96. #include <sys/time.h>
  97. #include <sys/errno.h>
  98. #include <sys/socket.h>
  99. #include <sys/uio.h>
  100. #include <netinet/in.h>
  101.  
  102. #include "tcpglue.h"
  103. #include "socket.internal.h"
  104.  
  105. /*
  106.  *    tuneable constants
  107.  */
  108. #define SOCK_IOINBUF_SIZE        128        /* Size of stdio input buffer */
  109. #define SOCK_IOOUTBUF_SIZE        128        /* Size of stdio output buffer */
  110.  
  111. static struct timeval select_poll = {0,0};
  112.  
  113. /*
  114.  *    s_fdopen() - open a stdio stream on a socket
  115.  */
  116. Ptr
  117. s_fdopen(fd, type)
  118.     int fd;
  119.     char *type;
  120. {
  121. #pragma unused(type)
  122.     SocketPtr sp;
  123.     
  124. #if    SOCK_STDIO_DEBUG >= 3
  125.     dprintf("s_fdopen: opening on fd %d\n",fd);
  126. #endif
  127.     if (! sock_good_fd(fd)) 
  128.     {
  129.         (void)sock_err(EBADF);
  130.         return(NULL);
  131.     }
  132.         
  133.     sp = &sockets[fd];
  134.     if (is_stdio(sp)) 
  135.         return((Ptr)sp);
  136.     
  137.     sp->inbuf = NewPtr(SOCK_IOINBUF_SIZE);
  138.     if (sp->inbuf == NULL) 
  139.     {
  140.         errno = ENOMEM;
  141.         return(NULL);
  142.     }
  143.     sp->outbuf = NewPtr(SOCK_IOOUTBUF_SIZE);
  144.     if (sp->outbuf == NULL) 
  145.     {
  146.         DisposPtr(sp->inbuf);
  147.         errno = ENOMEM;
  148.         return(NULL);
  149.     }
  150.     
  151.     sp->inbufptr  = sp->inbuf;
  152.     sp->inbufcount  = 0;
  153.     sp->outbufptr = sp->outbuf;
  154.     sp->outbufcount = 0;
  155.     
  156.     sp->ioerr = false;
  157.     sp->ioeof = false;
  158.  
  159.     return((Ptr)sp);
  160. }
  161.  
  162. /*
  163.  *    s_fileno()
  164.  */
  165. s_fileno(sp)
  166.     SocketPtr sp;
  167. {
  168. #if    SOCK_STDIO_DEBUG >= 3
  169.     dprintf("s_fileno:  on FILE * %08x\n",sp);
  170. #endif
  171.     if (! is_stdio(sp)) 
  172.     {
  173.         return(sock_err(EBADF));
  174.         return(EOF);
  175.     }
  176. #if    SOCK_STDIO_DEBUG >= 5
  177.     dprintf("   returning fd %d\n",sp->fd);
  178. #endif
  179.     return(sp->fd);
  180. }
  181.  
  182. /*
  183.  *    s_fgetc()
  184.  *
  185.  */
  186. s_fgetc(sp)
  187.     SocketPtr sp;
  188. {
  189.     char c;    
  190.         
  191.     if (stdio_read(sp, &c, 1) != 1)
  192.         return(EOF);
  193.         
  194.     return(c);
  195. }
  196.  
  197. /*
  198.  *    s_ungetc()
  199.  *
  200.  */
  201. s_ungetc(c, sp)
  202.     char c;
  203.     SocketPtr sp;
  204. {
  205.     
  206. #if    SOCK_STDIO_DEBUG >=3
  207.     dprintf("s_ungetc: %08x\n",sp);
  208. #endif
  209.  
  210.     if (! is_stdio(sp)) 
  211.     {
  212.         (void)sock_err(EBADF);
  213.         return(EOF);
  214.     }
  215.  
  216.     if (sp->ioeof)        /* Once an EOF; Always an EOF */
  217.         return(EOF);
  218.         
  219.     /*
  220.      *    Pop onto buffer, if there is room. 
  221.      */
  222.     if (sp->inbufptr == sp->inbuf)
  223.         return(EOF);
  224.     else 
  225.     {
  226.         *(sp->inbufptr++) = c;
  227.         sp->inbufcount++;
  228.         return(0);
  229.     }
  230. }
  231.  
  232. /*
  233.  *    s_fread()
  234.  */
  235. s_fread(buffer, size, nitems, sp)
  236.     char *buffer;
  237.     int size,nitems;
  238.     SocketPtr sp;
  239. {
  240.     return(stdio_read(sp, buffer, size*nitems));
  241. }
  242.     
  243. /*
  244.  *    stdio_read()
  245.  *
  246.  *    Buffered i/o.  Read buflen chars into buf.
  247.  *  Returns length read, EOF on error.
  248.  */
  249. static
  250. stdio_read(sp, buffer, buflen)
  251.     SocketPtr sp;
  252.     char *buffer;
  253.     int buflen;
  254. {
  255.     unsigned long tocopy;
  256.     Ptr buf;
  257.     unsigned long len;
  258.     int cache = false;    /* a flag ===> read into sp->inbuf */
  259.  
  260. #if    SOCK_STDIO_DEBUG >=3
  261.     dprintf("stdio_read: %08x for %d bytes\n",sp,buflen);
  262. #endif    
  263.  
  264.     if (! is_stdio(sp)) 
  265.     {
  266.         (void)sock_err(EBADF);
  267.         return(EOF);
  268.     }
  269.  
  270.     if (sp->ioeof)        /* Once an EOF; Always an EOF */
  271.         return(EOF);
  272.  
  273.     /*
  274.      *    return already buffered characters
  275.      */
  276.     if (sp->inbufcount != 0) 
  277.     {
  278.         tocopy = min(sp->inbufcount, buflen);
  279.         bcopy(sp->inbufptr, buffer, tocopy);
  280.         sp->inbufptr += tocopy;
  281.         sp->inbufcount -= tocopy;
  282.         return(tocopy);
  283.     }
  284.  
  285.     if (buflen > SOCK_IOINBUF_SIZE) 
  286.     {
  287.         /*
  288.          *    Read into user's buffer
  289.          */
  290.         buf = buffer;
  291.         len = buflen;
  292.     }
  293.     else 
  294.     {
  295.         /*
  296.          *    Read into stdio buffer
  297.          */
  298.         cache = true;
  299.         buf     = sp->inbuf;
  300.         len        = SOCK_IOINBUF_SIZE;
  301.     }
  302.  
  303.     len = s_read(sp->fd, buf, len);
  304.     switch(len) 
  305.     {
  306.         case -1:
  307.             sp->ioerr = true;
  308.             return(EOF);
  309.             
  310.         case 0:
  311.             sp->ioeof = true;
  312.             return(EOF);
  313.     }
  314.     if (cache) 
  315.     {
  316.         tocopy = min(buflen, len);
  317.         bcopy(sp->inbuf, buffer, tocopy);    /* copy to client's buffer */
  318.         sp->inbufcount     = len - tocopy;
  319.         sp->inbufptr     = sp->inbuf + tocopy;
  320.         return(tocopy);
  321.     }
  322.     return(len);            
  323. }
  324.  
  325.  
  326. /*
  327.  *    s_fputc()
  328.  *
  329.  */
  330. s_fputc(c, sp)
  331.     char c;
  332.     SocketPtr sp;
  333. {
  334.     if (stdio_write(sp, &c, 1) == EOF)
  335.         return(EOF);
  336.         
  337.     return(c);
  338. }
  339.                 
  340. /*
  341.  *    s_fprintf()
  342.  *
  343.  */
  344. s_fprintf(sp,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12)
  345.     SocketPtr sp;
  346.     char *fmt;
  347.     char *a1,*a2,*a3,*a4,*a5,*a6,*a7,*a8,*a9,*a10,*a11,*a12;
  348. {
  349.     int len;
  350.     char buf[1000];
  351.     
  352.     (void) sprintf(buf,fmt,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12);
  353.     len = strlen(buf);
  354.     return(stdio_write(sp, buf, len));
  355. }
  356.  
  357. /*
  358.  *    s_fwrite()
  359.  *
  360.  */
  361.  
  362. s_fwrite(buffer, size, nitems, sp)
  363.     char *buffer;
  364.     int size,nitems;
  365.     SocketPtr sp;
  366. {
  367.     return(stdio_write(sp, buffer, size*nitems));
  368. }
  369.  
  370. /*
  371.  *    stdio_write()
  372.  *
  373.  *    Buffered i/o.  Move buflen chars into stdio buf., writing out as necessary.
  374.  *    Returns # of characters written, or EOF.
  375.  */
  376. static
  377. stdio_write(sp, buffer, buflen)
  378.     SocketPtr sp;
  379.     char *buffer;
  380.     unsigned long buflen;
  381. {
  382.     long buffree;
  383.     struct iovec iov[2];
  384.     
  385. #if    SOCK_STDIO_DEBUG >=3
  386.     dprintf("stdio_write: %08x for %d bytes\n",sp,buflen);
  387. #endif    
  388.  
  389.     if (! is_stdio(sp))
  390.     {
  391.         (void) sock_err(EBADF);
  392.         return(EOF);
  393.     }
  394.     
  395.     /* will the new stuff fit in the buffer? */
  396.     buffree = SOCK_IOOUTBUF_SIZE - sp->outbufcount;
  397.     if (buflen < buffree)
  398.     {
  399.         /* yes...add it in */
  400.         bcopy(buffer, sp->outbufptr, buflen);
  401.         sp->outbufptr += buflen;
  402.         sp->outbufcount += buflen;
  403.         return(buflen);
  404.     }
  405.     else
  406.     {
  407.         /* no...send both buffers now */
  408.         iov[0].iov_len = sp->outbufcount;
  409.         iov[0].iov_base = sp->outbuf;
  410.         iov[1].iov_len = buflen;
  411.         iov[1].iov_base = buffer;
  412.         /* hide the 'error' generated by a non-blocking write */
  413.         if (s_writev(sp->fd,&iov[0],2) < 0 && errno != EINPROGRESS)
  414.         {
  415.             sp->ioerr = true;
  416.             return(EOF);
  417.         }
  418.  
  419.         sp->outbufptr = sp->outbuf;
  420.         sp->outbufcount = 0;
  421.  
  422.         return(buflen);
  423.     }
  424. }
  425.  
  426. /*
  427.  *    s_fflush()
  428.  *
  429.  */
  430. s_fflush(sp)
  431.     SocketPtr sp;
  432. {
  433. #if    SOCK_STDIO_DEBUG >=3
  434.     dprintf("s_fflush: %08x\n",sp);
  435. #endif
  436.     if (! is_stdio(sp))
  437.     {
  438.         (void)sock_err(EBADF);
  439.         return(EOF);
  440.     }
  441.     
  442.     if (sp->outbufcount == 0)
  443.         return(0);
  444.  
  445.     if (s_write(sp->fd,sp->outbuf,sp->outbufcount) < 0)
  446.         /* hide the 'error' generated by non-blocking I/O */
  447.         if (errno != EINPROGRESS)
  448.         {
  449.             sp->ioerr = true;
  450.             return(EOF);
  451.         }
  452.  
  453.     sp->outbufptr = sp->outbuf;
  454.     sp->outbufcount = 0;
  455.     return(0);
  456. }
  457.  
  458. /*
  459.  *    s_fclose() - close the stdio stream AND the underlying socket
  460.  */
  461. s_fclose(sp)
  462.     SocketPtr sp;
  463. {    
  464. #if    SOCK_STDIO_DEBUG >=3
  465.     dprintf("s_fclose: %08x\n",sp);
  466. #endif
  467.     
  468.     if (s_fflush(sp) == EOF) /* flush validates sp */
  469.         return(EOF);
  470.  
  471.     if (sp->inbuf != NULL) DisposPtr(sp->inbuf);
  472.     if (sp->outbuf != NULL) DisposPtr(sp->outbuf);
  473.     
  474.     return(s_close(sp->fd));
  475. }
  476.  
  477. /*
  478.  *    s_ferror()
  479.  */
  480. s_ferror(sp)
  481.     SocketPtr sp;
  482. {
  483.     if (! is_stdio(sp))
  484.     {
  485.         (void)sock_err(EBADF);
  486.         return(EOF);
  487.     }
  488.     return(sp->ioerr);
  489. }
  490.  
  491. /*
  492.  *    s_feof()
  493.  */
  494. s_feof(sp)
  495.     SocketPtr sp;
  496. {
  497.     if (! is_stdio(sp))
  498.     {
  499.         (void)sock_err(EBADF);
  500.         return(EOF);
  501.     }    
  502.     return(sp->ioeof);
  503. }
  504.  
  505. /*
  506.  *    s_clearerr()
  507.  */
  508. s_clearerr(sp)
  509.     SocketPtr sp;
  510. {    
  511.     if (! is_stdio(sp))
  512.     {
  513.         (void)sock_err(EBADF);
  514.         return(EOF);
  515.     }
  516.     sp->ioerr = false;
  517.     sp->ioeof = false;
  518. }
  519.  
  520.